// var 声明的变量可以赋值任意对象
// void main() {
//   var t;

//   t = "hi world";
//   t = 1000;
//   print(t);
// }

// dynamic和Object不同的是
// dynamic声明的对象编译器会提供所有可能的组合, 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错
// dynamic a;
// Object b;
// void main() {
//   a = "";
//   b = "";
//   printLength();
// }

// printLength() {
//   print(a.length);
//   // Error: The getter 'length' isn't defined for the class 'Object'.
//   // print(b.length);
// }

// 一个 final 变量只能被设置一次，两者区别在于：const 变量是一个编译时常量，final变量在第一次使用时被初始化。
// 被final或者const修饰的变量，变量类型可以省略
// void main() {
//   final str = "hi world";
//   // final String str = "hi world";
//   const str1 = "hi world";
//   //const String str1 = "hi world";

//   print(str);
//   print(str1);
// }

// 函数也是对象，并且有一个类型Function
// 函数可以赋值给变量或作为参数传递给其他函数

// Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理，注意，函数返回值没有类型推断
// typedef bool CALLBACK(int atomicNumber);

// //不指定返回类型，此时默认为dynamic，不是bool
// isNoble(int atomicNumber) {
//   return atomicNumber > 0;
// }

// void test(CALLBACK cb) {
//   print(cb(-1));
// }

// void main() {
//   // Error: The top level function has type 'dynamic Function(int)' that isn't of expected type 'bool Function(int)'.
//   test(isNoble);
// }

// 函数作为变量
// var say = (str) {
//   print(str);
// };

// void main() {
//   say("hello");
// }

// 函数作为参数传递
// void execute(var callback) {
//   callback();
// }

// void main() {
//   execute(() => print("hi"));
// }

// 可选的位置参数
// String say(String from, String msg, [String device]) {
//   var result = '$from says $msg';
//   if (device != null) {
//     result = '$result with a $device';
//   }
//   return result;
// }

// void main() {
//   print(say('Bob', 'Howdy')); //结果是： Bob says Howdy

//   print(say(
//       'Bob', 'Howdy', 'smoke signal')); //结果是：Bob says Howdy with a smoke signal
// }

// 可选的命名参数
// 定义函数时，使用{param1, param2, …}，放在参数列表的最后面，用于指定命名参数
// 注意，不能同时使用可选的位置参数和可选的命名参数
// void enableFlags({bool bold, bool hidden}) {
//   print(bold);
//   print(hidden);
// }

// void main() {
//   enableFlags(bold: true);
//   enableFlags(bold: true, hidden: false);
// }

// Future与JavaScript中的Promise非常相似，表示一个异步操作的最终完成（或失败）及其结果值的表示
// 异步处理成功了就执行成功的操作，异步处理失败了就捕获错误或者停止后续操作。
// 一个Future只会对应一个结果，要么成功，要么失败
// void main() {
//   // Future.delayed 创建了一个延时任务
//   Future.delayed(new Duration(seconds: 2), () {
//     return "hi";
//   }).then((value) => print(value));
// }

// 需要等待多个异步任务都执行结束后才进行一些操作
// Future.wait，它接受一个Future数组参数，只有数组中所有Future都执行成功后，才会触发then的成功回调，
// 只要有一个Future执行失败，就会触发错误回调
// void main() {
//   Future.wait([
//     // 2秒后返回结果
//     Future.delayed(new Duration(seconds: 2), () {
//       return "hello";
//     }),
//     // 4秒后返回结果
//     Future.delayed(new Duration(seconds: 4), () {
//       return " world";
//     })
//   ]).then((results) {
//     print(results[0] + results[1]);
//   }).catchError((e) {
//     print(e);
//   });
// }

//先分别定义各个异步任务
// Future<String> login(String userName, String pwd) {
//   //用户登录
// }
// Future<String> getUserInfo(String id) {
//   //获取用户信息
// }
// Future saveUserInfo(String userInfo) {
//   // 保存用户信息
// }

// void main() {
//   // 地狱回调
//   login("alice", "******").then((id) {
//     //登录成功后通过，id获取用户信息
//     getUserInfo(id).then((userInfo) {
//       //获取用户信息后保存
//       saveUserInfo(userInfo).then(() {
//         //保存用户信息，接下来执行其它操作
//       });
//     });
//   });

// // 使用Future消除Callback Hell
//   login("alice", "******").then((id) {
//     return getUserInfo(id);
//   }).then((userInfo) {
//     return saveUserInfo(userInfo);
//   }).then((e) {
//     //执行接下来的操作
//   }).catchError((e) {
//     //错误处理
//     print(e);
//   });
// }

// async用来表示函数是异步的，定义的函数会返回一个Future对象，可以使用then方法添加回调函数。
// await 后面是一个Future，表示等待该异步任务完成，异步完成后才会往下走；await必须出现在 async 函数内部。

// 使用async/await消除callback hell
// task() async {
//   try {
//     String id = await login("alice", "******");
//     String userInfo = await getUserInfo(id);
//     await saveUserInfo(userInfo);
//   } catch (e) {
//     //错误处理
//     print(e);
//   }
// }

// Stream 也是用于接收异步事件数据
// 在执行异步任务时，可以通过多次触发成功或失败事件来传递结果数据或错误异常。
// Stream 常用于会多次读取数据的异步任务场景，如网络内容下载、文件读写等
void main() {
  Stream.fromFutures([
// 1秒后返回结果
    Future.delayed(new Duration(seconds: 1), () {
      return "hello 1";
    }),
    // 抛出一个异常
    Future.delayed(new Duration(seconds: 2), () {
      throw AssertionError("Error");
    }),
    // 3秒后返回结果
    Future.delayed(new Duration(seconds: 3), () {
      return "hello 3";
    })
  ]).listen((data) {
    print(data);
  }, onError: (e) {
    print(e);
  }, onDone: () {});
}
